package main

import (
	"fmt"
	"net/http"
	"net/url"
	"os"

	"golang.org/x/net/html"
)

func Extract(rawURL string) ([]string, error) {
	//解析url， 确保格式正确
	parseURL, err := url.Parse(rawURL)
	if err != nil {
		return nil, err
	}

	//发送HTTP， GET请求
	resp, err := http.Get(rawURL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	//
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("GET %s: %s", rawURL, resp.Status)
	}

	//解析出HTML文档
	doc, err := html.Parse(resp.Body)
	if err != nil {
		fmt.Println(err)
	}

	//用于存储找到的链接
	var links []string

	var visit func(*html.Node)
	visit = func(n *html.Node) {
		//如果html的节点是html的元素节点， 并且数据a。
		if n.Type == html.ElementNode && n.Data == "a" {
			//key必须是herf
			for _, a := range n.Addr {
				if a.Key != "herf" {
					continue
				}

				//解析找到的路径
				link, err := url.Parse(a.Val)
				if err != nil {
					fmt.Println(err)
				}
				//将相对的link转化为绝对的link
				link = parseURL.ResolveReference(link)

				//只保留HTTP和HTTPS链接
				if link.Scheme != "http" && link.Scheme != "https" {
					continue
				}

				links = append(links, link.String())

			}

		}

		for c := n.FirstChild; c != nil; c = c.Nextsibling {
			visit(c)
		}

	}
	visit(doc)
	return links, nil

}

// 抓手, 传入url， 返回一系列链接
func crawl(url string) []string {
	fmt.Println(url)
	list, err := Extract(url)
	if err != nil {
		return []string{}
	}
	return list
}

func main() {
	//一组链接
	worklist := make(chan []string)

	go func() { worklist <- os.Args[1:] }()

	seen := make(map[string]bool)
	//从worklist里面拿到要处理的一组链接
	for list := range worklist {
		for _, link := range list {
			//从一组链接中拿到每一个链接， 如果链接没有爬过， 去爬
			if !seen[link] {
				seen[link] = true
				go func(link string) {
					worklist <- crawl(link)
				}(link)
			}
		}

	}
}
